﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using PlaydeezGames.Common;

namespace IslandInterloper.Engine
{
    internal class Avatar : GameClient
    {
        private static AvatarState XElementToState(XElement element)
        {
            return (AvatarState)Enum.Parse(typeof(AvatarState), element.Value);
        }
        #region Avatar State
        public AvatarState State
        {
            get;
            set;
        }
        #endregion
        #region Docked Island
        public int DockedIslandID
        {
            get;
            set;
        }
        #endregion
        #region Position
        private Location position;
        public ILocation Position
        {
            get
            {
                return position;
            }
            set
            {
                position.X = value.X;
                position.Y = value.Y;
            }
        }
        #endregion
        #region Day
        private int day;
        public int Day
        {
            get
            {
                return day;
            }
            set
            {
                day = value;
            }
        }
        #endregion
        #region Avatar Islands
        private AvatarIslands knownIslands = null;
        public AvatarIslands KnownIslands
        {
            get
            {
                return knownIslands;
            }
        }
        #endregion
        #region Direction
        private Heading direction = null;
        public Heading Direction
        {
            get
            {
                return direction;
            }
            set
            {
                direction.Degrees = value.Degrees;
            }
        }
        #endregion
        #region Ship
        private string ship = string.Empty;
        public string Ship
        {
            get
            {
                return ship;
            }
        }
        #endregion
        #region Days At Sea
        private int daysAtSea = 0;
        public int DaysAtSea
        {
            get
            {
                return daysAtSea;
            }
            set
            {
                daysAtSea = value;
            }
        }
        #endregion
        #region Speed
        private string speed;
        public string Speed
        {
            get
            {
                return speed;
            }
            set
            {
                speed = value;
            }
        }
        #endregion
        #region BoundForIsland
        private int boundForIslandId;
        public int BoundForIslandID
        {
            get
            {
                return boundForIslandId;
            }
            set
            {
                boundForIslandId = value;
            }
        }
        #endregion
        #region Inventory
        private AvatarCommodities inventory;
        public AvatarCommodities Inventory
        {
            get
            {
                return inventory;
            }
        }
        #endregion
        #region Crew
        private AvatarCrewmembers crew;
        public AvatarCrewmembers Crew
        {
            get
            {
                return crew;
            }
        }
        #endregion
        #region Constructors
        internal Avatar(Game theGame)
            : base(theGame)
        {
            State = AvatarState.Docked;
            double distance = double.MaxValue;
            DockedIslandID = Game.Config.NullIslandId;
            boundForIslandId = Game.Config.NullIslandId;
            position = Location.Midpoint(new Location(Game.Config.MinimumIslandX, Game.Config.MinimumIslandY), new Location(Game.Config.MaximumIslandX, Game.Config.MaximumIslandY));
            foreach (int islandId in Game.Islands.Keys)
            {
                Island island = Game.Islands[islandId];
                if (Location.Distance(position, island.Position) < distance)
                {
                    DockedIslandID = island.ID;
                    distance = Location.Distance(position, island.Position);
                }
            }
            position.X = Game.Islands[DockedIslandID].Position.X;
            position.Y = Game.Islands[DockedIslandID].Position.Y;
            day = Game.Config.AvatarStartDay;
            knownIslands = new AvatarIslands(Game);
            VisitIsland(DockedIslandID);
            knownIslands.Annotate(DockedIslandID, Game.Config.StartingIslandAnnotation);
            knownIslands.ToggleBookMark(DockedIslandID);
            direction = new Heading(Game.Config.InitialHeading);
            ship = Game.Ships.GenerateShip();
            inventory = new AvatarCommodities(Game);
            speed = Game.Config.InitialSpeed;
            crew = new AvatarCrewmembers(Game);
        }
        public void ToggleIslandBookMark(int theIslandID)
        {
            knownIslands.ToggleBookMark(theIslandID);
        }
        public void AnnotateIsland(int theIslandID, string theNote)
        {
            knownIslands.Annotate(theIslandID, theNote);
        }
        public void VisitIsland(int theIslandID)
        {
            knownIslands.Visit(theIslandID, Day);
        }
        public void LocateIsland(int theIslandID)
        {
            knownIslands.Locate(theIslandID, Day);
        }
        internal Avatar(Game theGame, XElement element)
            : base(theGame)
        {
            FromXElement(element);
        }
        #endregion
        #region Serialization
        private void FromXElement(XElement element)
        {
            State = XElementToState(element.Element(GameXNames.state));
            if (State != AvatarState.Uninitialized)
            {
                DockedIslandID = Utilities.XElementToInt(element.Element(GameXNames.dockedIsland));
                position = new Location(element.Element(GameXNames.position));
                day = Utilities.XElementToInt(element.Element(GameXNames.day));
                knownIslands = new AvatarIslands(Game, element.Element(GameXNames.knownIslands));
                direction = new Heading(element.Element(GameXNames.direction));
                ship = element.Element(GameXNames.ship).Value;
                daysAtSea = Utilities.FromStringToInt(element.Element(GameXNames.daysAtSea).Value);
                speed = element.Element(GameXNames.speed).Value;
                boundForIslandId = Utilities.FromStringToInt(element.Element(GameXNames.boundFor).Value);
                inventory = new AvatarCommodities(Game, element.Element(GameXNames.commodities));
                crew = new AvatarCrewmembers(Game, element.Element(GameXNames.crew));
            }
        }
        public override XElement ToXElement(XName xName)
        {
            XElement result = new XElement(xName,
                new XElement(GameXNames.state,State.ToString())
                );
            if(State!=AvatarState.Uninitialized)
            {
                result.Add(new XElement(GameXNames.dockedIsland, DockedIslandID));
                result.Add(position.ToXElement(GameXNames.position));
                result.Add(new XElement(GameXNames.day, day.ToString()));
                result.Add(knownIslands.ToXElement(GameXNames.knownIslands));
                result.Add(direction.ToXElement(GameXNames.direction));
                result.Add(new XElement(GameXNames.ship, ship));
                result.Add(new XElement(GameXNames.daysAtSea, daysAtSea));
                result.Add(new XElement(GameXNames.speed, speed.ToString()));
                result.Add(new XElement(GameXNames.boundFor, BoundForIslandID.ToString()));
                result.Add(inventory.ToXElement(GameXNames.commodities));
                result.Add(crew.ToXElement(GameXNames.crew));
            }
            return result;
        }
        #endregion

    }
}
